/* 
 * File:   StyleSheet.cpp
 * Author: H4314
 * 
 * Created on 24 avril 2012, 08:13
 */

#include "StyleSheet.h"

// Construit une feuille de style à partir du noeud xsl rootSheet
StyleSheet::StyleSheet(Element * rootSheet) {
    ConstructTemplate((Node *) rootSheet);
}

StyleSheet::~StyleSheet() {
    map<string, Template *>::iterator it;
    
    for(it = templates.begin(); it != templates.end(); it++)
        delete it->second;
    
    templates.clear();
}

// Ajoute proprement un template à la map
void StyleSheet::addTemplate(Template * templ) {
    templates.insert(pair<string, Template *>(templ->getElementMatchedName(), templ));
}

// Applique les transformations au sous-arbre de racine xmlNode (récursif)
// Retourne l'arbre html nouvellement alloué en mémoire
list<Node *> StyleSheet::Transform(Node * xmlNode) {
    list<Node *>::const_iterator it, it2;
    Element * element = dynamic_cast<Element *>(xmlNode);
    list<Node *> result;
    
    // Le noeud existe
    if(xmlNode != NULL)
    {
        // Le noeud est un element
        if(element != NULL)
        {
            Template * templ = findTemplate(xmlNode);
            
            // On parcourt les enfants de l'élement courant node
            for(it = element->getChildren().begin(); it != element->getChildren().end(); it++)
            {
                list<Node *> newNodeList = Transform(*it);
                for(it2 = newNodeList.begin(); it2 != newNodeList.end(); it2++)
                    result.push_back(*it2);

            }
            
            // Un template a été trouvé : on l'applique
            if(templ != NULL)
                return templ->Apply(result);
        }
        // Le noeud est un contenu
        else
        {
            Content * content = dynamic_cast<Content *>(xmlNode);
            Content * newContent = new Content(content->getText());
            result.push_back((Node *) newContent);
        }
    }
    
    return result;
}

// Cherche si un template match le noeud et le retourne, sinon retourne NULL
Template * StyleSheet::findTemplate(Node * node) {
    Element * element = dynamic_cast<Element *>(node);
    map<string, Template *>::const_iterator it;
    
    // Le noeud est un element
    if(element != NULL)
    {
        it = templates.find(element->getName());
        if(it != templates.end())
            return it->second;
    }

    return NULL;
}

// Charge la liste des templates à partir de la racine xslNode
void StyleSheet::ConstructTemplate(Node * xslNode) {
    list<Node *>::const_iterator it;
    Element * element = dynamic_cast<Element *>(xslNode);
    
    if(element != NULL)
    {
        // Le noeud est un element TEMPLATE : on l'ajoute
        if(element->getNameSpace() == NS_XSL && element->getName() == TEMPLATE)
            addTemplate(new Template(element));
        else
        {
            // On parcourt récursivement les enfants
            for(it = element->getChildren().begin(); it != element->getChildren().end(); it++)
                ConstructTemplate(*it);
        }
    }
}

ostream & operator<<(ostream & stream, const StyleSheet & ssheet) {
    map<string, Template *>::const_iterator it;
    int i = 1;
    
    cout << "\033[33m__________List of known templates__________\033[00m" << endl;
    for(it = ssheet.templates.begin(); it != ssheet.templates.end(); it++)
    {
        list<Node *>::const_iterator it2;
        list<Node *> nodesToDraw = ((it)->second)->Draw();
        
        cout << "\t\033[32m[[ Template n°" << setw(3) << setfill('0') << i++ << " ]]\033[00m" << endl;
        
        for(it2 = nodesToDraw.begin(); it2 != nodesToDraw.end(); it2++)
        {
            (*it2)->Draw(stream);
            stream << endl << endl;
        }
        
        // Clean It Up !
        Node::CleanItUp(nodesToDraw);
    }
    
    return stream;
}
